﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Globalization;
using System.Windows.Forms;

namespace EVDashboard
{
    //
    // Implements the ISystem (BMS) for HardyBMS
    //
    public class HardyBMS : ISystem
    {
        #region Private Declarations
        private bool Log_Enabled = true;
        private bool Sim_Enabled = false;
        private string sdCard = null;
        private string line;
        private string ResponseText;

        public BmsConfig StoredBMSConfig = new BmsConfig();
        public BmsData InvalidBMSData = new BmsData();
        public BmsData StoredBMSData = new BmsData();
        public int ReceivedBmsMode;
        public int ReceivedBmsState;
        public bool BMSValidConfig;
        public int BMS_Balance_Cycles;
        public Stream p_stream;
//        public MainForm p_mainForm;
        private MainForm mainForm;

        private List<List<float>> voltage;
        //private List<int> reserved;
        //private List<int> exceptions;

        //private static int PACK_VOLTS = 0;
       // private static int PACK_SOC = 1;
        //private static int PACK_TEMP = 2;
       // private static int PACK_SERIES = 3;
        private List<int> pack = new List<int>();

       // private static int TIME_SECOND = 0;
       // private static int TIME_MINUTE = 1;
       // private static int TIME_HOUR = 2;
       // private static int TIME_DAY = 3;
       // private static int TIME_SOC = 4;
       // private static int TIME_AMPS = 5;
        private List<int> time = new List<int>();

        //private float voltageFactor = 100f; // data multiple either 10 or 100 
        //private float amperageFactor = 10f;

        //private string batteryType;
//        public AlertForm aform; 

        public char lastCommandReceived;

        #endregion


    //NOT SURE WHAT THIS IS USED FOR
//        public HardyBMS()
  //      {
    //    }

        public void SendRunMode()  // called from charge done form
        {
            AddBMSCommand(RunBMS, RunBMS.Length);
        }


        public class BMSCommand
        {
            public byte[] commandbyte;
            public int length;
        }

//        public void SetBatteryType(string batteryType)
  //      {
    //        this.batteryType = batteryType;
      //  }

        public BmsData Parse(string line)
        {  // data will come in either as a charactr string end wiht <13>, o
            // 
        //    if (Log_Enabled)
         //   {
         //       Util.LogData(line + "\r\n", sdCard);
         //   }
      
            this.line = line;
            ResponseText = "";
            //ResponseText = line;
            //
            // convert back to byte array
            int NumberChars = line.Length;

            byte[] bytes = new byte[(NumberChars / 2) + 2];
            for (int i = 0; i < NumberChars; i += 2)
            {
                try
                {
                    bytes[i / 2] = Convert.ToByte(line.Substring(i, 2), 16);
                }
                catch
                {
                    bytes[i / 2] = 0;
                }
            }
            if (bytes[0] == (byte)'/')
            {   if (Log_Enabled)
                {
                  Util.LogData(line + "\r\n", sdCard);
                }
      
        
                StringBuilder textline = new StringBuilder();
                CultureInfo ci = new CultureInfo("es-ES", true);
             //   textline.Append("(" + (line.Length/2).ToString() + ") ");
             //   if (NumberChars > 10)
             //       NumberChars = 10;
                for (int x = 0; x < NumberChars / 2; x++)
                    textline.AppendFormat(ci, "{0:x2} ", bytes[x]);
                //ResponseText = textline.ToString();
            }
            else
            {
      
                StringBuilder textline = new StringBuilder();
            //    textline.Append("(" + (line.Length / 2).ToString() + ") ");
                for (int x = 0; x < (NumberChars / 2); x++)
                    textline.Append((char)bytes[x]);
                StoredBMSConfig.Status = textline.ToString();
                if (Log_Enabled)
                {
                    Util.LogData(ResponseText + "\r\n", sdCard);
                }
            }
            if ((line.Length / 2) > 3)
            {
                if ((bytes[0] == (byte)'/') & (bytes[1] == (byte)'C'))
                { //  ResponseText = "GOT CONFIG, len:" + (line.Length/2).ToString();
                    lastCommandReceived = (char) bytes[1];
                    ReceivedBmsMode = bytes[3];
                    ReceivedBmsState = bytes[4];
                    SetHardyBMSConfig(bytes, line.Length / 2);
                }
                if ((bytes[0] == (byte)'/') & (bytes[1] == (byte)'K') & line.Length>6)
                {    lastCommandReceived = (char) bytes[1];
                     ResponseText = "GOT OK, mode:" + bytes[3];
                    lastCommandReceived = (char)bytes[2];
                    ReceivedBmsMode = bytes[3];
                    ReceivedBmsState = bytes[4];
                }
                if ((bytes[0] == (byte)'/') & (bytes[1] == (byte)'A') & line.Length > 8)
                {    lastCommandReceived = (char)bytes[1];

                    StoredBMSConfig.Status = "GOT Alert code:" + bytes[6];
                    lastCommandReceived = (char)bytes[1];
                    ReceivedBmsMode = bytes[3];
                    ReceivedBmsState = bytes[4];
              //      aform.Show();
                    ProcessBMSAlert(bytes, line.Length / 2, mainForm);
                }
                if ((bytes[0] == (byte)'/') & (bytes[1] == (byte)'D'))
                {   //ResponseText = "GOT DATA, len:" + (line.Length/2).ToString();
                    lastCommandReceived = (char)bytes[1];

                    if (ParseHardyBMSData(bytes, line.Length / 2) == 0)
                    {
                        //ResponseText += " Error ";
                    }
                    StringBuilder textline = new StringBuilder();
                    CultureInfo ci = new CultureInfo("es-ES", true);

                    for (int i = 0; i < line.Length/2; i++)
                    { textline.AppendFormat(ci, "{0:x2} ", bytes[i]);
                    } 
                    //ResponseText = textline.ToString();

                }
                    

            }
            StoredBMSConfig.Status = ResponseText;

            mainForm.Invoke(new MainForm.SetDataDeleg(mainForm.m_DataReceived), new object[] { StoredBMSData });
            mainForm.Invoke(new MainForm.SetConfigDeleg(mainForm.m_ConfigReceived), new object[] { StoredBMSConfig });

            return StoredBMSData;
        }

        public bool HasConfig()
        { return true;
        }

        public void SetBmsSetup(BmsSetup bs)
        {
            Log_Enabled = bs.LogEnabled;
            Sim_Enabled = bs.SimEnabled;
            //not using battery type
        }

        public void Initialize(MainForm mf)
        {
            mainForm = mf;
       
        
            sdCard = Util.GetStorageCard();

           // StoredBMSData.uptime. new TimeSpan

            StoredBMSData.temp = 0;
            StoredBMSData.amps =0;
            StoredBMSData.voltage =0;
            //StoredBMSData.uptime.Seconds = 0;
            StoredBMSData.soc = 0;
            StoredBMSData.line = "";
            ReceivedBmsMode = 0; // set to unknwown.
            voltage = new List<List<float>>();
       
            List<float> remote = null;
            remote = new List<float>();
            remote.Add(0f);
            voltage.Add(remote);
        
            StoredBMSData.voltages = voltage;

            StoredBMSConfig.Status = "Initalized Data";
            StoredBMSConfig.OverVoltage = 0;
            StoredBMSConfig.UnderVoltage = 0;
            StoredBMSConfig.BalanceVoltage = 0;
            StoredBMSConfig.HighTemp = 0;
            StoredBMSConfig.MaxKwH = 0;
            StoredBMSConfig.NumberOfBoards = 1;
            StoredBMSConfig.Boards= new List<int>();
            StoredBMSConfig.Boards.Add(1);
            StoredBMSConfig.Boards.Add(2);
            StoredBMSConfig.Boards.Add(3);
            StoredBMSConfig.Boards.Add(4);
            StoredBMSConfig.Boards.Add(5);
            StoredBMSConfig.Boards.Add(0);
            StoredBMSConfig.Boards.Add(0);
            StoredBMSConfig.Mode = "";
    //        StoredBMSConfig.State = "";
         //   StoredBMSConfig.LogEnabled = true;
            BMSValidConfig = false;
            InvalidBMSData = StoredBMSData;
            mainForm.Invoke(new MainForm.SetDataDeleg(mainForm.m_DataReceived), new object[] { StoredBMSData });


        }

        private int ParseHardyBMSData(byte[] bytes, int length)
        {   int index;
            int x;
            int cellsperboard = 0; 
            if (BMSValidConfig == false)
             { return 0; }
            // now parse the darn BMS data

            if (length < 15)
                return 0;

            byte pec_calc;
            // check pec
            pec_calc = 0;
            for (x = 3; x <= (bytes[2]-2) + 3; x++)
                pec_calc = crc8_pic(pec_calc, bytes[x]);
            if (!Sim_Enabled & (pec_calc != bytes[x]))
            {
                throw new System.Exception("CRC ERROR " + pec_calc.ToString() + " " + bytes[x].ToString() + x.ToString());
            }
            bool updateconfig = false;
            if (ReceivedBmsState != (int) bytes[0+3])
               updateconfig = true;
            if (ReceivedBmsMode != (int) bytes[1+3])
                updateconfig = true;
            
            ReceivedBmsMode = ( (int) bytes[0+3]);
            ReceivedBmsState = ( (int) bytes[1+3]);
            if (updateconfig)
            {
                if (ReceivedBmsMode == 0x40)
                    StoredBMSConfig.Mode = "Restart";
                else if (ReceivedBmsMode == 0x49)
                    StoredBMSConfig.Mode = "Stop";
                else if (ReceivedBmsMode == 0x42)
                    StoredBMSConfig.Mode = "Run";
                else if (ReceivedBmsMode == 0x43)
                    StoredBMSConfig.Mode = "Balance";
                else
                    StoredBMSConfig.Mode = "--";

             //   StoredBMSConfig.State = ReceivedBmsState.ToString();
                   StoredBMSConfig.Status += ReceivedBmsState.ToString();
            }

            int Seconds =  ((int)(bytes[0 + 3] * 256 + bytes[3 + 3]) );

            StoredBMSData.uptime = new TimeSpan(0, 0, Seconds);
                
            float totalpack = ((float)(bytes[4 + 3] * 256 + bytes[5 + 3]) / 100);
            StoredBMSData.voltage = totalpack;

            int packtemp = ((int)(bytes[6 + 3] * 256 + (int)bytes[7 + 3]) );
            StoredBMSData.temp = packtemp;
            //  int [6] is monitor state

            //  long [7-8] is power * 10
            byte[] temparray = new byte[2];
            temparray[0] = bytes[10+3];
            temparray[1] = bytes[9+3];

            short pwr = BitConverter.ToInt16(temparray, 0);

            StoredBMSData.kwh = ((float) pwr)/10;
            
                       
            // int [9] is soc 0-100
            StoredBMSData.soc = (float) ((int)bytes[11 + 3]);
            
            // long [9-10] = amps  12+3
            temparray = new byte[2];
            temparray[0] = bytes[16];
            temparray[1] = bytes[15];

            short amps = BitConverter.ToInt16(temparray,0);
            StoredBMSData.amps = (float) (amps);

            BMS_Balance_Cycles = (int)bytes[14 + 3];


            index = 16+3 ;
            voltage = new List<List<float>>();
            List<float> remote = null;
            remote = new List<float>();
  // START NEW CODE
            int cellcounter = 0;
            
            for (x = 1; x<= (StoredBMSConfig.NumberOfBoards); x++)
            {
               // remote = new List<float>();
          //      cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[x - 1]);
                if (x == 1) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[0]);
                if (x == 2) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[1]);
                if (x == 3) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[2]);
                if (x == 4) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[3]);
                if (x == 5) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[4]);
                if (x == 6) cellsperboard = 0;
                if (x == 7) cellsperboard = 0;
    
                for (int y = 1; y<= cellsperboard; y ++)
                {
                  Int32 thisval = bytes[index++] * 256 + bytes[index++];
                  Int32 thisbat = thisval * 15;
                  float thisfloat = ((float)thisbat)/10000;
                  decimal dval = Math.Round(Convert.ToDecimal(thisfloat), 2); // +"V";

                  if (cellcounter == 8)
                  {
                      voltage.Add(remote);
                      remote = new List<float>();
                      cellcounter = 0;
                  }
                  cellcounter++;
                  remote.Add((float) dval);
                  if (index > length)
                      return 0;  //must be data short
                }
                      
            }
            voltage.Add(remote);
    // END NEW CODE

    ///START OLD CODE        
            
/*            for (x = 1; x<= (StoredBMSConfig.NumberOfBoards); x++)
            {    remote = new List<float>();
                if (x == 1) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[0]);
                if (x == 2) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[1]);
                if (x == 3) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[2]);
                if (x == 4) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[3]);
                if (x == 5) cellsperboard = Convert.ToInt32(StoredBMSConfig.Boards[4]);
                if (x == 6) cellsperboard = 0 ;
                if (x == 7) cellsperboard =  0 ;
    
                for (int y = 1; y<= cellsperboard; y ++)
                {
                    Int32 thisval = bytes[index++] * 256 + bytes[index++];
                  Int32 thisbat = thisval * 15;
                  float thisfloat = ((float)thisbat)/10000;
                  if (y==7)
                  {
                      voltage.Add(remote);
                      remote = new List<float>();
                  }
                  decimal dval =  Math.Round(Convert.ToDecimal(thisfloat), 2); // +"V";
                  remote.Add((float) dval);
                  if (index > length)
                      return 0;
                }
                voltage.Add(remote);
                      
            }

        //END OLD CODE
*/
            StoredBMSData.voltages = voltage;
            return 1;
        }
        public List<string> GetAlertList()
        {
            List<string> thislist = new List<string>();
            thislist.Add("Alert 1");
            thislist.Add("Alert 2");
            return thislist;
            
        }

        
           
        private void ProcessBMSAlert(byte[] bytes, int length, MainForm mainForm)
        {
            BmsAlert myAlert = new BmsAlert();
            if (length < 12)
            {
                myAlert.Notice = "Alert Length Error";
                myAlert.AlertCode = 0;
                myAlert.Severity = 0;
                //
                
                mainForm.Invoke(new MainForm.SetAlertDeleg(mainForm.m_AlertReceived), new object[] { myAlert });
            }
            else
            {
                
                myAlert.AlertCode = bytes[5];
                myAlert.Severity = bytes[6];
                myAlert.Notice = "";
                for (int x = 7; x <= (bytes[2] - 6 + 7); x++)
                    myAlert.Notice += (char)bytes[x];


                // MyChildForm is the one I'm looking for 
              //  aform.AddAlert("NEW ALERT ADDED");
               // if (!aform.Visible)
               //     aform = new AlertForm(this);
                //aform.Show();
                //aform.Activate();
                if (myAlert.AlertCode == 21)  //charge end
                {
                   // ChargeComplete CC = new ChargeComplete(this);  // THIS CREATES A NEW WINDOW FOR EACH MESSAGSE.
                   // CC.ShowDialog()
                    MessageBox.Show("Charge Complete", "Charge Complete");
                    SendRunMode();
                }
                else
                {
                    if (myAlert.Severity >= 4)  //LOG=1, WARN =4, ERR = 8
                    {
                        mainForm.Invoke(new MainForm.SetAlertDeleg(mainForm.m_AlertReceived), new object[] { myAlert });
                    }
                }
           }
        }

        private int SetHardyBMSConfig(byte[] myconfig, int length)
        {
            int x;
            if (length < 33)
                return 0;
      
            byte pec_calc;
            // check pec
            pec_calc = 0;

            
            //            for ( x = 3; x <= 30 + 3; x++)
            for ( x = 3; x <= (myconfig[2]-2) + 3; x++)
                pec_calc = crc8_pic(pec_calc, myconfig[x]);
            if (!Sim_Enabled & (pec_calc != myconfig[x]))
            {
                throw new System.Exception("CRC ERROR " + pec_calc.ToString() + " " + myconfig[x].ToString() + x.ToString());
                   
            }
            else
            {
                BMSValidConfig = true;
                // OVInt = 1
                // OverVoltage_config.Text = myconfig[1 + 3].ToString();
                ReceivedBmsMode = ((int)myconfig[0 + 3]);
                if (ReceivedBmsMode == 0x40)
                    StoredBMSConfig.Mode = "Restart";
                else if (ReceivedBmsMode == 0x49)
                    StoredBMSConfig.Mode = "Stop";
                else if (ReceivedBmsMode == 0x42)
                     StoredBMSConfig.Mode = "Run";
                else if (ReceivedBmsMode == 0x43)
                    StoredBMSConfig.Mode = "Balance";
                else
                    StoredBMSConfig.Mode = "--";


                ReceivedBmsState = ((int)myconfig[1 + 3]);
                //StoredBMSConfig.State = ReceivedBmsState.ToString();
                StoredBMSConfig.Status += ReceivedBmsState.ToString();
                
                StoredBMSConfig.OverVoltage = ((float)(((int)myconfig[3 + 3]) * 24) / 1000);
                // UVInt = 3
                StoredBMSConfig.UnderVoltage = ((float)(((int) myconfig[5 + 3]) * 24)/1000);
                // EE_BAL_INT 5  // def = 0xAA
                
                StoredBMSConfig.BalanceVoltage = ((float)(((int) myconfig[7 + 3]) * 24)/1000);
                // EE_TEMP_INT 13 // 1 byte int for high temp degrees C
                
                StoredBMSConfig.HighTemp = (int) myconfig[15 + 3];
                //  EE_NUM_BOARDS_INT 16 //  1 to 8
                StoredBMSConfig.NumberOfBoards = (int) myconfig[18 + 3];
                // EE_CELLS_IN_BOARD_0_INT 17 //  4-12
                StoredBMSConfig.Boards = new List<int>();
                for ( x = 19; x< 19 + 7 ; x++)
                {
                    StoredBMSConfig.Boards.Add ( (int) myconfig[x + 3] );
                }
                // EE_CURRENT_MONITOR_ENABLED 28 //  current_monitor_enabled
           //     StoredBMSConfig.CurrentSensor = (myconfig[30 + 3] == 1);
                // EE_CURRENT_COUNT_UP 	29 //  current_count_up
           //     StoredBMSConfig.KwHCountUp = (myconfig[31 + 3] == 1);
                // EE_KWATT_HOURS_MAX_INT 	30 //  kwatt_hours_max, default 13  
                StoredBMSConfig.MaxKwH = (float) ((int)myconfig[32 + 3]);
                
            }
            return 1;
        }

        public byte crc8_pic(byte old_crc, byte newbyte)
        {
            byte i;
            byte data;

            data = (byte)((byte)old_crc ^ (byte)newbyte);

            for (i = 0; i < 8; i++)
            {
                if ((data & 0x80) != 0)
                {
                    data <<= 1;
                    data ^= 0x07;
                }
                else
                {
                    data <<= 1;
                }
            }
            return (data);
        }

        private BmsData GetBmsData()
        {
            return StoredBMSData;
        }

        static readonly byte[] GetOK = { (byte)'/', (byte)'k', 0, 13 };
        static readonly byte[] TestMsg = { (byte)'/', (byte)'k', 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, 13 };
        static readonly byte[] RequestConfig = { (byte)'/', (byte)'c', 0, 13 };
        static readonly byte[] RequestData = { (byte)'/', (byte)'d', 0, 13 };
        static readonly byte[] RestartBMS = { (byte)'/', (byte)'M', 2, 0x040, 0, 13 };
        static readonly byte[] RunBMS = { (byte)'/', (byte)'M', 2, 0x042, 0, 13 };

        List<BMSCommand> CmdQ = new List<BMSCommand>();
        // HARDY ADD THIS CODE:
     
        private void ReadFunction()
        {

           Read(p_stream, mainForm);
        }
        
        public void Manager(Stream stream)
        {
 
            p_stream = stream;
            Thread myReadThread = new Thread(new ThreadStart(ReadFunction));
                myReadThread.Start();


            NetworkStream btStream = (NetworkStream)stream;
            
            // first need to guess at status, probably booting...
            string mystatus = "Starting BMS Manger...";
            mainForm.Invoke(new MainForm.SetTextDeleg(mainForm.WriteStatus), new object[] {mystatus });
            Thread.Sleep(1000);
            lastCommandReceived = (char) 0; // set flag to unknown
            mystatus = "Query BMS Status...";
            mainForm.Invoke(new MainForm.SetTextDeleg(mainForm.WriteStatus), new object[] { mystatus });
            Thread.Sleep(100);

            BMSCommand mycommand = new BMSCommand();
            mycommand.commandbyte = GetOK;
            mycommand.length = GetOK.Length;

            CmdQ.Add(mycommand);
            if (!Process1Q( stream))
            {   mystatus = "No BMS Response...";
                mainForm.Invoke(new MainForm.SetTextDeleg(mainForm.WriteStatus), new object[] { mystatus });
                if (Log_Enabled)
                    Util.LogData(mystatus + "\r\n", sdCard);
                CmdQ.Clear();
            }
            mycommand.commandbyte = RequestConfig;
            mycommand.length = RequestConfig.Length;

            CmdQ.Add(mycommand);
            if (!Process1Q(stream))
            {
                mystatus = "No Config Response...";
                mainForm.Invoke(new MainForm.SetTextDeleg(mainForm.WriteStatus), new object[] { mystatus });
                if (Log_Enabled)
                    Util.LogData(mystatus + "\r\n", sdCard);
                CmdQ.Clear();
            }

            mycommand.commandbyte = RequestData;
            mycommand.length = RequestData.Length;

            CmdQ.Add(mycommand);
            if (!Process1Q(stream))
            {
                mystatus = "No Data Response...";
                mainForm.Invoke(new MainForm.SetTextDeleg(mainForm.WriteStatus), new object[] { mystatus });
                if (Log_Enabled)
                    Util.LogData(mystatus + "\r\n", sdCard);
                CmdQ.Clear();
            }

            do 
            {
               if (CmdQ.Count >0 )
                {
                    if (!Process1Q(stream)) 
                    {
                        mystatus = "No Cmd Response...";
                        mainForm.Invoke(new MainForm.SetTextDeleg(mainForm.WriteStatus), new object[] { mystatus });
                        mainForm.Invoke(new MainForm.SetDataDeleg(mainForm.m_DataReceived), new object[] { InvalidBMSData });

                        //  if (Log_Enabled)
                       //     Util.LogData(mystatus + "\r\n", sdCard);
                        CmdQ.Clear();
                    }
                    Thread.Sleep(1000);
                }
                Thread.Sleep(50);
                if ((CmdQ.Count == 0) && ((ReceivedBmsMode == 0x42) || (ReceivedBmsMode == 0x43)))  //RUN OR BALANCE
                {
                    mycommand.commandbyte = RequestData;
                    mycommand.length = RequestData.Length;

                    CmdQ.Add(mycommand);
                }
             }  while (true);
        }

        private bool Process1Q(Stream stream)
        {
            int ThisCmdLength;
              NetworkStream btStream = (NetworkStream)stream;

              if (CmdQ.Count >= 1)
              {   
                  byte[] ThisCmd = new byte[100];
                  for (int x = 0; x < CmdQ[0].length; x++)
                  {
                      ThisCmd[x] = CmdQ[0].commandbyte[x];
                  }
                  ThisCmdLength = CmdQ[0].length;
                  CmdQ.Remove(CmdQ[0]);

                  lastCommandReceived = (char) 0;


                  StringBuilder sb = new StringBuilder();
                 // Byte b;
                  CultureInfo ci = new CultureInfo("es-ES", true);
                  for (int x = 0; x < ThisCmdLength; x++)
                  {
                      sb.AppendFormat(ci, "{0:x2}", ThisCmd[x]);
                  }
                  if (Log_Enabled)
                      Util.LogData("Cmd: " + sb + "\r\n", sdCard);

                  
                  
                  //  for (int x = 0; x < 5; x++)
                  {
                      for (int i = 0; i < ThisCmdLength; i++)
                      {
                          btStream.WriteByte(ThisCmd[i]);
                          btStream.Flush();
                          //Thread.Sleep(2);
                      } 
                    for (int y = 0; y < 50; y++)
                    {
                        if (lastCommandReceived == (char) 0)
                        {
                            Thread.Sleep(100);
                        }
                    }
                    if (lastCommandReceived != (char)0)
          //             x = 6;
                    { }
                  }
                  if (lastCommandReceived == (char) 0)
                      return false;
                  else
                      return true;
              }
              return true;
        }
        
        public void AddBMSCommand(byte[] Command, int length)
        {    byte[] thiscommand = new byte[length];
             thiscommand = Command;

                StringBuilder sb = new StringBuilder();
              //  Byte b;
                CultureInfo ci  = new CultureInfo("es-ES",true);
                for (int x = 0; x< length; x++)
                {                    
                    sb.AppendFormat( ci, "{0:x2}", thiscommand[x]) ; 
                }
                if (Log_Enabled)
                    Util.LogData("CMD: " + sb + "\r\n", sdCard);

                BMSCommand mycommand = new BMSCommand();
                mycommand.commandbyte = Command;
                mycommand.length = length;

             CmdQ.Add(mycommand);
        }

        public void Read(Stream stream, MainForm mainForm)
        {   byte[] mba = new byte[200];
            int mba_index = 0;
         
            NetworkStream btStream = (NetworkStream)stream;
            StringBuilder sb = new StringBuilder();
            do
            {
                while (!btStream.DataAvailable)
                {
                    Thread.Sleep(100);
                    // TODO if more than 5 seconds out of range (sound)
                }
                
                Byte b = (byte) btStream.ReadByte();
                mba[mba_index++] = b;
                CultureInfo ci  = new CultureInfo("es-ES",true);
                sb.AppendFormat( ci, "{0:x2}", b) ; 

                if (((mba[0] != (byte)'/') & (b == 13)) |  // this case handles unformatted strings
                  ((mba[0] == (byte)'/') & (mba_index >= 2) & (mba[2] + 4 == (byte)mba_index)))

                {
                    string line = sb.ToString();
                   // string notice = "This is called";
                    Parse(line);
                    //mainForm.Invoke(new MainForm.SetTextDeleg(mainForm.m_teststring), new object[] { notice });

                    sb = new StringBuilder();
                    mba_index = 0;
                }
                if (mba_index >= 199)  //throw out garbage before exception
                {
                    mba_index = 0;
                    sb = new StringBuilder();
                }    
               
            }
            while (true);
        }

        private List<List<float>> GetVoltages()
        {
            return voltage;
        }

        private int GetTemp()
        {
            // average temps?
            //return pack[PACK_TEMP];
            return StoredBMSData.temp ;
        }

        // Sum the voltage from each remote
        private float GetVoltage()
        {
         //   int volts = 0;
         //   for (int i = 0; i < voltage.Count; i++)
          //  {
           //     volts += pack[(4 * i) + PACK_VOLTS];
          //  }
//
  //          return volts / voltageFactor;
            return StoredBMSData.voltage;
        }

        private TimeSpan GetUptime()
        {
            return new TimeSpan(GetDay(), GetHour(), GetMinute(), GetSecond());
        }

        private int GetSecond()
        {
            //return time[TIME_SECOND];
            return  0 ;
        }

        private int GetMinute()
        {
            //return time[TIME_MINUTE];
            return 0;
        }

        private int GetHour()
        {
            //return time[TIME_HOUR];
            return  0 ;
        }

        private int GetDay()
        {
            //            return time[TIME_DAY];
            return  0 ;
        }

        // Return the state of charger %
        private float GetSOC()
        {
            //            return (float)time[TIME_SOC];
            return (float)0;
        }

        private float GetAmps()
        {
            //            return (float)time[TIME_AMPS] / amperageFactor;
            return (float) 21 ;
        }


     
        public string GetSimFileName()
        {
            return "hardybms_sim.csv";
        }

        public BmsConfig GetConfig()
        {
            return StoredBMSConfig;
        }

        public void WriteConfig(BmsConfig bmsConfig)
        {
            StoredBMSConfig = bmsConfig;
            
            // recieve the bmsconfig and write to the bms
            int x;
            byte[] myconfig = new byte[100];
            byte pec_calc;

            for (x = 0; x < 100; x++)
                myconfig[x] = 0;

            myconfig[0] = (byte)'/';
            myconfig[1] = (byte)'C';
            myconfig[2] = (byte)32;  // fixed length



            myconfig[3] = 1;  // this is the program byte
            // OVInt = 1
            myconfig[1 + 3] = (byte)((int) ((( StoredBMSConfig.OverVoltage ) * 1000)) / 24);
            // UVInt = 3
            myconfig[3 + 3] = (byte)((int) ((( StoredBMSConfig.UnderVoltage ) * 1000)) / 24);
                // EE_BAL_INT 5  // def = 0xAA
            myconfig[5 + 3] = (byte)((int) (((StoredBMSConfig.BalanceVoltage) * 1000)) / 24);
            // EE_TEMP_INT 13 // 1 byte int for high temp degrees C

            myconfig[13 + 3] = (byte)Convert.ToInt32(StoredBMSConfig.HighTemp);
//            myconfig[14 + 3] = 0x14;
  //          myconfig[15 + 3] = 0x15;

            //  EE_NUM_BOARDS_INT 16 //  1 to 8
            myconfig[16 + 3] = (byte)((int)(StoredBMSConfig.NumberOfBoards));
            myconfig[16 + 3] = (byte)((int)(2));
            // EE_CELLS_IN_BOARD_0_INT 17 //  4-12
            myconfig[17 + 3] = (byte)  ((int)(StoredBMSConfig.Boards[0]));

            // EE_CELLS_IN_BOARD_1_INT 18 //  4-12
            myconfig[18 + 3] = (byte)  ((int)(StoredBMSConfig.Boards[1]));
            // EE_CELLS_IN_BOARD_2_INT 19 //  4-12
            myconfig[19 + 3] = (byte)  ((int) (StoredBMSConfig.Boards[2]));
            // EE_CELLS_IN_BOARD_3_INT 20 //  4-12
            myconfig[20 + 3] = (byte)  ((int) (StoredBMSConfig.Boards[3]));
            // EE_CELLS_IN_BOARD_4_INT 21 //  4-12
            myconfig[21 + 3] = (byte)  ((int) (StoredBMSConfig.Boards[4]));
            // EE_CELLS_IN_BOARD_5_INT 22 //  4-12
            myconfig[22 + 3] = 0;
            // EE_CELLS_IN_BOARD_6_INT 23 //  4-12
            myconfig[23 + 3] = 0;

        //    if (StoredBMSConfig.CurrentSensor)
                myconfig[28 + 3] = (byte)1;  //Always have current sensor.
        //    else
        //        myconfig[28 + 3] = (byte)0;

       //     // EE_CURRENT_COUNT_UP 	29 //  current_count_up
       //     if (StoredBMSConfig.KwHCountUp)
       //         myconfig[29 + 3] = (byte)1;
       //     else
                myconfig[29 + 3] = (byte)0;  //Always count down
            // EE_KWATT_HOURS_MAX_INT 	30 //  kwatt_hours_max, default 13  
            myconfig[30 + 3] = (byte) ((int) (StoredBMSConfig.MaxKwH));
            myconfig[31 + 3] = 0;
            myconfig[32 + 3] = 0;
            myconfig[33 + 3] = 0;

            //ok, send it to the bms
            // need to recalculate CRC
            pec_calc = 0;
            for (x = 3; x <= (30 + 3); x++)
                pec_calc = crc8_pic(pec_calc, myconfig[x]);

            myconfig[34] = pec_calc;

            myconfig[35] = 13;
//SEND CONFIG COMMAND:                        
            AddBMSCommand(myconfig, 36);
//UPDATE LOCAL CONFIG DATA
            AddBMSCommand(RequestConfig, RequestConfig.Length);
// SEND NEW MODE OF OPERATION
            byte[] newcmd = new byte[20];
            newcmd[0] = ((byte)'/');
            newcmd[1] = ((byte)'M');
            newcmd[2] = ((byte)2);
            if (StoredBMSConfig.Mode == "Restart")
                newcmd[3] = ((byte)0x40);
            else if (StoredBMSConfig.Mode == "Stop")
                newcmd[3] = ((byte)0x49);
            else if (StoredBMSConfig.Mode == "Run")
                newcmd[3] = ((byte)0x42);
            else if (StoredBMSConfig.Mode == "Balance")
                newcmd[3] = ((byte)0x43);
            else
                newcmd[3] = ((byte)0x49);  // needs some default
            newcmd[4] = ((byte)StoredBMSConfig.BalanceCycles);
            newcmd[5] = ((byte)13);
            AddBMSCommand(newcmd, 6);


        }
       

        public void BMSTest(BmsConfig bmsConfig)
        {   
            
            byte[] newcmd = new byte[20];
            newcmd[0] = ((byte)'/');
            newcmd[1] = ((byte)'M');
            newcmd[2] = ((byte)2);
            if (bmsConfig.Mode=="Restart")
                newcmd[3] = ((byte)0x40);
            else if (bmsConfig.Mode == "Stop")
                newcmd[3] = ((byte)0x49);
            else if (bmsConfig.Mode=="Run")
                newcmd[3] = ((byte)0x42);
            else if (bmsConfig.Mode == "Balance")
                newcmd[3] = ((byte)0x43);
            else
                newcmd[3] = ((byte)0x49);  // needs some default
            StoredBMSConfig.Mode = bmsConfig.Mode;
            newcmd[4] = ((byte)bmsConfig.BalanceCycles);
            StoredBMSConfig.BalanceCycles= newcmd[4];
            newcmd[5] = ((byte)13);
            AddBMSCommand(newcmd, 6);
        }
            
            
         //   AddBMSCommand(RequestData, RequestData.Length);
        

        public void BMSRestart()
        {
            AddBMSCommand(RestartBMS, RestartBMS.Length);
        }
    }
}
